package com.android.dwt.widget;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;

import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Display;
import android.view.GestureDetector;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnLongClickListener;
import android.view.View.OnTouchListener;
import android.view.WindowManager;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.TableLayout;
import android.widget.TableRow;
import android.widget.TextView;
import android.widget.Toast;

import com.android.dwt.R;
import com.android.dwt.ui.CalendarAct;
import com.android.dwt.ui.DayView;

public class CalendarView extends LinearLayout implements OnTouchListener, OnLongClickListener {
	
	private static final String TAG = "CalendarView";
	private static final int WEEK_NUM = 7;
	private static final String VIEW_TASK = "查看";
	
	// current selected date
	private Calendar mCal = Calendar.getInstance();
	private Calendar mToday = (Calendar) mCal.clone();
	private int mYear;		// this year
	private int mMonth;	// this month
	private int mDay;		// today
	
	private int mScreenWidth;
	private int mScreenHeight;
	
	private ArrayList<DayCell> mDays = new ArrayList<DayCell>();
	private boolean mMark = true;
	private TextView mCurView;
	private CalendarAct mCalAct;
	
	private View mView;
	private TextView mTitleMonth;
	private TableLayout mWeekLabel;
	private TableLayout mDayTable;
	private ImageButton mPrevious;
	private ImageButton mNext;
	
	
	private GestureDetector mGestureDetector = new GestureDetector(
			new GestureDetector.SimpleOnGestureListener() {

				@Override
				public boolean onFling(MotionEvent e1, MotionEvent e2,
						float velocityX, float velocityY) {
					
					// from right to left
					if (e1.getX() > e2.getX()) {
						
						Log.e(TAG, "from right to left");
						
						addMonth(1);
					}

					// from left to right
					if (e1.getX() < e2.getX()) {
						
						Log.e(TAG, "from left to right");
						
						addMonth(-1);
					}

					return true;
				}

			});
	
	private SimpleDateFormat mSdfDate = new SimpleDateFormat("yyyy-MM-dd");

	
	public CalendarView(Context context) {
		
		super(context);
		
		mCalAct = (CalendarAct) context;
		
		initView();
		
		refreshDate();
		
		updateView();
	}
	
	public CalendarView(Context context, AttributeSet attrs) {
		
		super(context, attrs);
		
		mCalAct = (CalendarAct) context;
		
		initView();
		
		refreshDate();
		
		updateView();
	}

	@Override
	protected void onDraw(Canvas canvas) {
		
		super.onDraw(canvas);
	}
	
	public void setDate(int year, int month, int day) {
		
		mCal.set(Calendar.YEAR, year);
		mCal.set(Calendar.MONTH, month);
		mCal.set(Calendar.DAY_OF_MONTH, day);
	}
	
	public boolean hasMark() {
		
		return mMark;
	}
	
	private void initView() {
		
		Display display = ((WindowManager) mCalAct.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
		mScreenWidth = display.getWidth();
		mScreenHeight = display.getHeight();
		
		mYear = mCal.get(Calendar.YEAR);
		mMonth = mCal.get(Calendar.MONTH);
		mDay = mCal.get(Calendar.DATE);

		mView = LayoutInflater.from(mCalAct).inflate(R.layout.calendar, this, true);
//		mView.setBackgroundResource(R.drawable.background);
		
		mTitleMonth = (TextView) mView.findViewById(R.id.tv_month);
		mWeekLabel = (TableLayout) mView.findViewById(R.id.tl_week);
		mDayTable = (TableLayout) mView.findViewById(R.id.tl_day_table);
		
		mPrevious = (ImageButton) mView.findViewById(R.id.previous);
		mNext = (ImageButton) mView.findViewById(R.id.next);
		
		// title
		mTitleMonth.setTextColor(0xff444444);
		mTitleMonth.setTextSize(24);
		mTitleMonth.setTypeface(null, Typeface.BOLD);
		
		// week
		mWeekLabel.getChildAt(0).setBackgroundResource(R.drawable.week);
		
		mDayTable.setBackgroundColor(0xffffffff);
		
		mPrevious.setOnClickListener(new OnClickListener() {
			
			@Override
			public void onClick(View v) {
				
				addMonth(-1);
			}
			
		});
		mPrevious.setOnTouchListener(new OnTouchListener() {
			
			@Override
			public boolean onTouch(View v, MotionEvent event) {
				
				if (event.getAction() == MotionEvent.ACTION_DOWN) {
					
					v.setBackgroundResource(R.drawable.previous_pressed);
					
				} else if (event.getAction() == MotionEvent.ACTION_UP) {
					
					v.setBackgroundResource(R.drawable.previous);
				}

				return false;
			}
			
		});
		
		mNext.setOnClickListener(new OnClickListener() {
			
			@Override
			public void onClick(View v) {
				
				addMonth(1);
			}
			
		});
		mNext.setOnTouchListener(new OnTouchListener() {
			
			@Override
			public boolean onTouch(View v, MotionEvent event) {
				
				if (event.getAction() == MotionEvent.ACTION_DOWN) {
					
					v.setBackgroundResource(R.drawable.next_pressed);
					
				} else if (event.getAction() == MotionEvent.ACTION_UP) {
					
					v.setBackgroundResource(R.drawable.next);
				}

				return false;
			}
			
		});
		
	}
	
	private void addMonth(int step) {
		
		mCal.add(Calendar.MONTH, step);		// add 1 or -1
		
		if (mCal.get(Calendar.MONTH)==mMonth
				&& mCal.get(Calendar.YEAR)==mYear) {
			
			mMark = true;
			
			mCal.set(Calendar.DATE, mDay);		// set to today
			
			Cursor csr = mCalAct.mGa.getDbta().getDayTask(mSdfDate.format(mCal.getTime()));
			if (csr.getCount() == 0) {
				
				mCalAct.mViewTask.setEnabled(false);
				mCalAct.mViewTask.setText(VIEW_TASK);
				
			} else {
				
				mCalAct.mViewTask.setEnabled(true);
				mCalAct.mViewTask.setText(VIEW_TASK + " (" + csr.getCount() + ")");
			}
			
			mCalAct.mAddTask.setEnabled(true);
			
			csr.close();
			
		} else {
			
			mMark = false;
			
			mCalAct.mViewTask.setEnabled(false);
			mCalAct.mAddTask.setEnabled(false);
			mCalAct.mViewTask.setText(VIEW_TASK);
		}
		
		updateCalendar();
	}
	
	public void updateCalendar() {
		
		// enable today button or not
		updateTodayState();
		
		refreshDate();
		
		updateView();
	}
	
	private void updateView() {
		
		mDayTable.removeAllViews();
		
		// title (year+month)
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM");
		mTitleMonth.setText(sdf.format(mCal.getTime()));
		
		int index = 0;
		int rows = calculateRow(); 		Log.e(TAG, "number of rows: " + rows);
		
		Calendar cal = (Calendar) mCal.clone();
		for (int i=0; i<rows; i++) {
			
			TableRow tableRow = new TableRow(mCalAct);
			TableLayout.LayoutParams tlLP = new TableLayout.LayoutParams();
			tableRow.setLayoutParams(tlLP);
//			tableRow.setBackgroundColor(0xFFd4d4d4);
			
			TableRow.LayoutParams lp = new TableRow.LayoutParams(
					LayoutParams.FILL_PARENT,
					mScreenWidth/WEEK_NUM,
					1);
			
			for (int j=0; j<WEEK_NUM; j++) {
				
				DayCell dc = mDays.get(index++);		// always can be divided by 7
				int flag = dc.getFlag();
				
				TextView tv = new TextView(mCalAct);
				tv.setTag(dc);
				
				if (flag == DayCell.CURRENT_MONTH) {
					
					tv.setTextColor(0xff444444);
					cal.set(Calendar.MONTH, mCal.get(Calendar.MONTH));
					
				} else if (flag == DayCell.PREVIOUS_MONTH) {
					
					tv.setTextColor(0xffbbbbbb);
					cal.set(Calendar.MONTH, mCal.get(Calendar.MONTH)-1);
					
				} else if (flag == DayCell.NEXT_MONTH) {
					
					tv.setTextColor(0xffbbbbbb);
					cal.set(Calendar.MONTH, mCal.get(Calendar.MONTH)+1);
				}
				cal.set(Calendar.DATE, dc.getDayOfMonth());
				
//				tv.setTag(flag);
				tv.setTextSize(16f);
				tv.setTypeface(null, Typeface.BOLD);
				tv.setGravity(Gravity.CENTER);
				tv.setText(dc.toString());
				tv.setOnTouchListener(this);
				
				String date = mSdfDate.format(cal.getTime());
//				Log.e(TAG, "date string: " + date);
				if (mCalAct.mGa.getDbta().hasTask(date)) {	// has task
					
					if (cal.before(mToday)) {		// overdue event
						
						if (flag == DayCell.CURRENT_MONTH) {
							
							tv.setBackgroundResource(R.drawable.overdue_event);
							
						} else {
							
							tv.setBackgroundResource(R.drawable.overdue_last_month);
						}

						
					} else {
						
						if (flag == DayCell.CURRENT_MONTH) {
							
							tv.setBackgroundResource(R.drawable.event);
							
						} else {
							
							tv.setBackgroundResource(R.drawable.non_cur_event);
						}
						
					}
					
					tv.setTextColor(Color.WHITE);
				}
				
				if (flag==DayCell.CURRENT_MONTH
						&& dc.getDayOfMonth()==mCal.get(Calendar.DATE)) {
					
					mCurView = tv;
					
					if (mMark) {
						
    					markDay(mCurView);
					}
    					
				}
				
				tableRow.addView(tv, lp);
			}
			
			mDayTable.addView(tableRow);
		}
		
		Log.e(TAG, "now index= " + index);
		
		cal = null;
	}
	
	private int calculateRow() {
		
		int rows = 5;		// default number of rows
		
		Calendar cld = Calendar.getInstance();
		cld.setTime(mCal.getTime());
		
		Log.e(TAG, "current date is: " + mSdfDate.format(cld.getTime()));
		
		cld.set(Calendar.DATE, 1);		// go to first day of current month
		int firstDay = cld.get(Calendar.DAY_OF_WEEK);		// get week of the first day
		
		Log.e(TAG, "firstDay is: " + firstDay);
		
		int maxDays = cld.getActualMaximum(Calendar.DATE);		// get maximum days of current month
		cld.set(Calendar.DATE, maxDays);
		int lastDay = cld.get(Calendar.DAY_OF_WEEK);
		
		Log.e(TAG, "last Day is: " + lastDay);
		
		if (firstDay==Calendar.SUNDAY && lastDay==Calendar.SATURDAY) {		// 28 days in Feb
			
			rows = 4;
			
		} else if (firstDay > lastDay+1) {
			
			rows = 6;
			
		} else {
			
			rows = 5;
		}
		
		cld = null;
		
		return rows;
	}
	
	private void refreshDate() {
		
		Cursor csr = null;
		
		mDays.clear();
		
		Calendar cld = Calendar.getInstance();
		cld.setTime(mCal.getTime());
		
		cld.set(Calendar.DATE, 1);
		int firstDay = cld.get(Calendar.DAY_OF_WEEK);		// get week of first day
		
		// days of previous month
		if (firstDay > Calendar.SUNDAY) {
			
			cld.add(Calendar.DATE, Calendar.SUNDAY-firstDay);	
			
			for (int i=0; i<(firstDay-Calendar.SUNDAY); i++) {
				
				DayCell dc = new DayCell(cld.get(Calendar.DATE), DayCell.PREVIOUS_MONTH);
				String date = mSdfDate.format(cld.getTime());
				
				csr = mCalAct.mGa.getDbta().getDayTask(date);
				dc.setNumOfEvent(csr.getCount());
				
				mDays.add(dc);
				
				cld.add(Calendar.DATE, 1);
				
				csr.close();
			}
			
		}	// will go to the first day of current month
		
		Log.e(TAG, "size of previous month in this month: "+mDays.size());
		Log.e(TAG, "now date is: "+mSdfDate.format(cld.getTime()));
		
		// days of current month
		cld.set(Calendar.DATE, 1);
		int maxDays = cld.getActualMaximum(Calendar.DATE);
		
		Log.e(TAG, "number of days of this month: " + maxDays);
		
		for (int i=0; i<maxDays; i++) {
			
			DayCell dc = new DayCell(cld.get(Calendar.DATE), DayCell.CURRENT_MONTH);
			String date = mSdfDate.format(cld.getTime());
			
			csr = mCalAct.mGa.getDbta().getDayTask(date);
			dc.setNumOfEvent(csr.getCount());
			
			mDays.add(dc);
			
			cld.add(Calendar.DATE, 1);
			
			csr.close();
			
		}	// will go to the first day of next month
		
		Log.e(TAG, "after adding days of current month: " + mSdfDate.format(cld.getTime()));
		Log.e(TAG, "size of this month plus previous month: " + mDays.size());
		
		cld.add(Calendar.DATE, -1);		// reach to last day of this month
		int lastDay = cld.get(Calendar.DAY_OF_WEEK);	// get week of the last day of current month
		
		Log.e(TAG, "now date is: "+mSdfDate.format(cld.getTime()));
		
		// days of next month
		if (lastDay < Calendar.SATURDAY) {
			
			cld.add(Calendar.DATE, 1);		// go to the first day of next month
			
			for (int i=0; i<(Calendar.SATURDAY-lastDay); i++) {
				
				DayCell dc = new DayCell(cld.get(Calendar.DATE), DayCell.NEXT_MONTH);
				String date = mSdfDate.format(cld.getTime());
				
				csr = mCalAct.mGa.getDbta().getDayTask(date);
				dc.setNumOfEvent(csr.getCount());
				
				mDays.add(dc);
				
				cld.add(Calendar.DATE, 1);
				
				csr.close();
			}
			
		}
		
		Log.e(TAG, "size of all table: " + mDays.size());
		
		cld = null;
		
		return;
	}
	
	public void gotoToday() {
		
		mCal.setTime(mToday.getTime());
		
		mMark = true;
		
//		updateCalendar();
		addMonth(0);
	}
	
	public Calendar getCurrentDay() {
		
		return mCal;
	}
	
	private void markDay(TextView tv) {
		
		tv.setBackgroundResource(R.drawable.bg_select_day);
		tv.setTextColor(Color.WHITE);
	}
	
	private void updateTodayState() {
		
		if (!mCal.equals(mToday)) {
			
			mCalAct.setTodayEnabled(true);
			
		} else {
			
			mCalAct.setTodayEnabled(false);
		}
		
	}
	
	@Override
	public boolean dispatchTouchEvent(MotionEvent event) {
		
		Log.e(TAG, "dispatchTouchEvent is called!");

		if (mGestureDetector.onTouchEvent(event)) {
			
			Log.e(TAG, "gesture consumes this event");
			
//			event.setAction(MotionEvent.ACTION_CANCEL);
			
			return true;
		}

		return super.dispatchTouchEvent(event);		// false
	}

	@Override
	public boolean onTouch(View v, MotionEvent event) {
		
		Log.e(TAG, "onTouch Method is called");
		
		TextView tv = (TextView) v;
		
		String day = tv.getText().toString();
		DayCell dc = (DayCell) tv.getTag();
		int flag = dc.getFlag();
		
		if (event.getAction() == MotionEvent.ACTION_UP) {
			
			int month = mCal.get(Calendar.MONTH);
			
			if (flag == DayCell.PREVIOUS_MONTH) {
				
				mCal.add(Calendar.MONTH, -1);
				
			} else if (flag == DayCell.CURRENT_MONTH) {
				
				
			} else if (flag == DayCell.NEXT_MONTH) {
				
				mCal.add(Calendar.MONTH, 1);
			}
			mCal.set(Calendar.DATE, Integer.parseInt(day));
			
			// view task button state
			if (dc.hasEvent()) {
				
				mCalAct.mViewTask.setEnabled(true);
				mCalAct.mViewTask.setText(VIEW_TASK + " (" + dc.getNumOfEvent() + ")");
				
			} else {
				
				mCalAct.mViewTask.setEnabled(false);
				mCalAct.mViewTask.setText(VIEW_TASK);
			}
			
			// add task button state
			if (mCal.before(mToday)) {
				
				mCalAct.mAddTask.setEnabled(false);
				
			} else {
				
				mCalAct.mAddTask.setEnabled(true);
			}
			
			// today button state
			if (mCal.get(Calendar.MONTH) == month) {
				
				updateTodayState();
				
				mCurView = tv;
				
			} else {
				
				mMark = true;
				
				updateCalendar();
			}
			
			return true;
		}
		
		if (event.getAction() == MotionEvent.ACTION_DOWN) {
			
			DayCell cur = (DayCell) mCurView.getTag();
			if (cur.hasEvent()) {
				
				mCurView.setBackgroundResource(R.drawable.event);
				mCurView.setTextColor(Color.WHITE);
    			
			} else {
				
				mCurView.setBackgroundColor(Color.TRANSPARENT);
    			mCurView.setTextColor(0xff444444);
			}
			
			/*if (dc.hasEvent()) {
				
				tv.setBackgroundResource(R.drawable.day_with_event);
    			tv.setTextColor(Color.WHITE);
				
			} else {
				
				markDay(tv);
			}*/
			
			markDay(tv);
			
			
			/*// enable today button or not
			if (cld.get(Calendar.YEAR)==mYear
					&& cld.get(Calendar.MONTH)==mMonth
					&& cld.get(Calendar.DATE)==mDay) {
				
				((CalendarAct) mContext).setTodayEnabled(false);
				
			} else {
				
				((CalendarAct) mContext).setTodayEnabled(true);
			}*/
			
//			markDay(mCurView);
			
//			Toast.makeText(mContext, mSdfDate.format(cld.getTime()), Toast.LENGTH_SHORT).show();
			
			// start activity
			/*Intent i = new Intent(mContext, DayView.class);
			
//			i.putExtra("cal", gc);
			i.putExtra("selected_date", mSdfDate.format(cld.getTime()));
			
			mContext.startActivity(i);*/
			
			return true;
		}
		
		return false;
	}

	@Override
	public boolean onLongClick(View v) {
		
		Toast.makeText(mCalAct, "textview long click!", Toast.LENGTH_LONG).show();
		
//		Intent i = new Intent(mCalAct, DayView.class);
//		
////		i.putExtra("cal", gc);
//		i.putExtra("selected_date", mSdfDate.format(mCal.getTime()));
//		
//		mCalAct.startActivity(i);
		
		return false;
	}
	
	/*@Override
	public boolean onTouchEvent(MotionEvent event) {
		
		Log.e(TAG, "onTouchEvent is called!");
		
//		mGestureDetector.onTouchEvent(event);
		 
		return true;
	}*/
	
}
